const MazeMap = (mapSize, cellSize, app, stage, modeType) => {
  return new Promise((res, rej) => {
    const { Sprite, Container, utils } = PIXI;
    const { loader } = app;
    // 元素状态
    const CellType = {
      way: 1, // 路
      wall: 2, // 墙
    };

    // 生成初始迷宫地图
    const mapContainer = new Container();
    stage.addChild(mapContainer);

    let resTexture = null;

    // 生成整个地图
    const createMazeCells = () => {
      let mapCells = [];

      for (let i = 0; i < mapSize * mapSize; i++) {
        const x = i % mapSize,
          y = Math.floor(i / mapSize);
        const cell = {
          pos: { x, y },
          cell_type: CellType.wall,
        };
        mapCells.push(cell);
      }
      return mapCells;
    };

    // 迷宫节点集合
    let mapCells = [],
      startCell = null;
    const createMazeMap = () => {
      mapCells = createMazeCells();
      // 起点设置
      const { x, y } = getStartCell();
      startCell = mapCells[onPosToIndex(x, y)];
      createWay(startCell);
      if (modeType === 1) {
        createMode1([startCell]);
      } else if (modeType === 2) {
        createMode2([...getAroundCell(x, y)]);
      }
    };

    const createMode1 = (wayCells) => {
      if (wayCells.length === 0) {
        const { startWall, endWall } = setStartAndEnd(startCell);
        createMazeCellRender();
        res({
          mapContainer,
          checkCellIsWay,
          startWall,
          endWall,
        });
        return;
      } else {
        const { x, y } = wayCells[0].pos;
        const aroundCells = getAroundCell(x, y);
        if (aroundCells.length > 0) {
          // 随机获取一个进行下一步
          const cells =
            aroundCells[Math.floor(Math.random() * aroundCells.length)];

          cells.forEach((cell) => {
            const { x, y } = cell.pos;
            createWay(cell);
            if (x % 2 === 1 && y % 2 === 1) {
              wayCells.unshift(cell);
            }
          });
        } else {
          wayCells.shift();
        }
        createMode1(wayCells);
      }
    };

    const createMode2 = (aroundCells) => {
      if (aroundCells.length === 0) {
        const { startWall, endWall } = setStartAndEnd(startCell);
        createMazeCellRender();
        res({
          mapContainer,
          checkCellIsWay,
          startWall,
          endWall,
        });
        return;
      } else {
        const i = Math.floor(aroundCells.length * Math.random());
        const nextCells = aroundCells[i];

        aroundCells.splice(i, 1);
        const nc = nextCells[1];
        if (nc.cell_type === CellType.wall) {
          const { x, y } = nc.pos;
          const nextAroundCells = getAroundCell(x, y);
          aroundCells.push(...nextAroundCells);
          createWay(nc);
          createWay(nextCells[0]);
        }

        createMode2(aroundCells);
      }
    };

    const createMazeCellRender = () => {
      for (let i = 0; i < mapCells.length; i++) {
        const { cell_type, pos } = mapCells[i];
        const { x, y } = pos;
        const { wall1, wall2, way } = resTexture;

        if (cell_type === CellType.wall) {
          cellAddRender(
            Math.random() > 0.5 ? wall1.texture : wall2.texture,
            x,
            y
          );
        } else {
          cellAddRender(resTexture.way.texture, x, y);
        }
      }
    };

    const cellAddRender = (texture, x, y) => {
      let cellRender = new Sprite(texture);
      cellRender.width = cellSize;
      cellRender.height = cellSize;
      cellRender.x = x * cellSize;
      cellRender.y = y * cellSize;
      cellRender.name = `${x}_${y}`;
      mapContainer.addChild(cellRender);
    };

    // 验证是路
    const checkCellIsWay = (x, y) => {
      const cell = mapCells[onPosToIndex(x, y)];
      return !cell ? false : cell.cell_type === CellType.way;
    };
    // 设置起点与终点
    const setStartAndEnd = (startCell) => {
      const { x, y } = startCell.pos;

      const endCell = mapCells[onPosToIndex(mapSize - 1 - x, mapSize - 1 - y)];
      if (endCell.cell_type === CellType.wall) {
        createWay(endCell);
      }
      const { x: ex, y: ey } = endCell.pos;

      const startWall = getWallWay(x, y),
        endWall = getWallWay(ex, ey);
      createWay(startWall);
      createWay(endWall);
      return {
        startWall,
        endWall,
      };
    };

    // 获取起点终点外侧的墙
    const getWallWay = (x, y) => {
      if (x === 1) {
        return mapCells[onPosToIndex(0, y)];
      } else if (x === mapSize - 2) {
        return mapCells[onPosToIndex(mapSize - 1, y)];
      }

      if (y === 1) {
        return mapCells[onPosToIndex(x, 0)];
      } else if (y === mapSize - 2) {
        return mapCells[onPosToIndex(x, mapSize - 1)];
      }
    };

    // 获取四周的活跃节点
    const getAroundCell = (x, y) => {
      const ret = [];

      const upCell = mapCells[onPosToIndex(x, y - 2)];
      if (!!upCell && upCell.cell_type === CellType.wall) {
        ret.push([mapCells[onPosToIndex(x, y - 1)], upCell]);
      }

      const downCell = mapCells[onPosToIndex(x, y + 2)];
      if (!!downCell && downCell.cell_type === CellType.wall) {
        ret.push([mapCells[onPosToIndex(x, y + 1)], downCell]);
      }

      const leftCell = mapCells[onPosToIndex(x - 2, y)];
      if (!!leftCell && leftCell.cell_type === CellType.wall) {
        ret.push([mapCells[onPosToIndex(x - 1, y)], leftCell]);
      }

      const rightCell = mapCells[onPosToIndex(x + 2, y)];
      if (!!rightCell && rightCell.cell_type === CellType.wall) {
        ret.push([mapCells[onPosToIndex(x + 1, y)], rightCell]);
      }
      return ret;
    };

    // 将节点变成路
    const createWay = (cell) => {
      if (!cell) {
        return;
      }
      cell.cell_type = CellType.way;
    };
    // 坐标转换成下标
    const onPosToIndex = (x, y) => {
      if (x < 0 || y < 0 || x > mapSize - 1 || y > mapSize - 1) {
        return -1;
      }
      return mapSize * y + x;
    };

    // 获取起点
    const getStartCell = () => {
      // 起点用原来左边或者上边

      // 保证坐标在围墙之内，不取到四个角
      const i = Math.floor(Math.random() * ((mapSize - 1) / 2)) * 2 + 1;

      // 是否在左边，不然就在上边
      const isLeft = Math.random() > 0.5;

      return isLeft ? { x: 1, y: i } : { x: i, y: 1 };
    };

    if (!utils.TextureCache.way) {
      loader
        .add("way", "http://other.lookthis.cc/way.png")
        .add("wall1", "http://other.lookthis.cc/wall1.png")
        .add("wall2", "http://other.lookthis.cc/wall2.png")
        .load(loaded);
    } else {
      const { way, wall1, wall2 } = utils.TextureCache;
      resTexture = {
        way: {
          texture: way,
        },
        wall1: {
          texture: wall1,
        },
        wall2: {
          texture: wall2,
        },
      };
      createMazeMap();
    }

    function loaded(loader, resources) {
      resTexture = resources;
      createMazeMap();
    }
  });
};
